/*****************************************************************************
*
*  @file     IcuDriver.c
*  @brief    Icu驱动
*            1. 负责实现Icu驱动
*
*  @author   潘学林
*  @email                                        
*  @version  V0.000
*  @date     2022/4/21
*  @license  /
*----------------------------------------------------------------------------*
*  Remark         : Description                                              *
*----------------------------------------------------------------------------*
*  Change History :                                                          *
*  <Date>     | <Version> | <Author>       | <Description>                   *
*----------------------------------------------------------------------------*
*  2022/4/21  | 0.000     | 潘学林         | 创建文件                        *
*----------------------------------------------------------------------------*
*
*****************************************************************************/

/* Includes ------------------------------------------------------------------*/

#include "IcuDriver.h"

/* Micros/Enumerate/Structures -----------------------------------------------*/

/* Variables -----------------------------------------------------------------*/

/* ICU控制信息 */
static ICU_DRIVER_CTRL_INFO icuCtrlInfo;

/* Functions -----------------------------------------------------------------*/

/*****************************************
* 内部函数
*****************************************/

/**
  * @brief  Icu驱动控制参数初始化
  * @param  None
  * @retval None
  */
static void IcuDriver_ParameterInit(void)
{
	icuCtrlInfo.periodInfo.PPState = FALSE;
	icuCtrlInfo.periodInfo.pingCounter = 0;
	icuCtrlInfo.periodInfo.pongCounter = 0;
	icuCtrlInfo.periodInfo.period = 0;
	icuCtrlInfo.dutyInfo.riseCounter = 0;
	icuCtrlInfo.dutyInfo.downCounter = 0;
	icuCtrlInfo.dutyInfo.duty = 0;
	icuCtrlInfo.outputTimeout.periodCount = 0; 
	icuCtrlInfo.outputTimeout.dutyCount = 0;
}

#if 0
/**
  * @brief  Icu初始化
  * @param  None
  * @retval None
  */
static void IcuDriver_Timer2Init(void)
{
	/* TIMER2 configuration: input capture mode -------------------
	the external signal is connected to TIMER2 CH0 pin(PA6)
	the rising edge is used as active edge
	the TIMER2 CH0CV is used to compute the frequency value
	------------------------------------------------------------ */
	timer_ic_parameter_struct timer_icinitpara;
	timer_parameter_struct timer_initpara;
	
	rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_AF);
	rcu_periph_clock_enable(RCU_TIMER2);
	
	/*configure PA6(TIMER2 CH0) as alternate function*/
	gpio_init(ICU_Port, GPIO_MODE_IPU, GPIO_OSPEED_MAX, ICU_Pin); 
	
	timer_deinit(TIMER2);
	/* initialize TIMER init parameter struct */
	timer_struct_para_init(&timer_initpara);
	/* TIMER2 configuration */
	timer_initpara.prescaler         = ICU_PRESCALER;
	timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection  = TIMER_COUNTER_UP;
	timer_initpara.period            = ICU_COUNTER_MAX;
	timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
	timer_init(TIMER2, &timer_initpara);

	/* TIMER2  configuration */
	/* initialize TIMER channel input parameter struct */
	timer_channel_input_struct_para_init(&timer_icinitpara);
	
	/* TIMER2 CH0 input capture configuration */
	timer_icinitpara.icpolarity  = TIMER_IC_POLARITY_RISING;
	timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
	timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
	timer_icinitpara.icfilter    = 0x0;
	timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);

	/* auto-reload preload enable */
	timer_auto_reload_shadow_enable(TIMER2);
	/* clear channel 0 interrupt bit */
	timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH0);
	/* channel 0 interrupt enable */
	timer_interrupt_enable(TIMER2,TIMER_INT_CH0);
	nvic_irq_enable(TIMER2_IRQn, 1, 1);
	/* TIMER2 counter enable */
	timer_enable(TIMER2);
}

#else

/**
  * @brief  Icu初始化
  * @param  None
  * @retval None
  */
static void IcuDriver_Timer2Init(void)
{
	/* TIMER2 configuration: input capture mode -------------------
	the external signal is connected to TIMER2 CH0 pin(PA6)
	the rising edge is used as active edge
	the TIMER2 CH0CV is used to compute the frequency value
	------------------------------------------------------------ */
	timer_ic_parameter_struct timer_icinitpara;
	timer_parameter_struct timer_initpara;
	
	rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_AF);
	rcu_periph_clock_enable(RCU_TIMER2);
	
	/*configure PA6(TIMER2 CH0) as alternate function*/
	gpio_init(ICU_CH_0_Port, GPIO_MODE_IPU, GPIO_OSPEED_MAX, ICU_CH_0_Pin); 
	/*configure PA7(TIMER2 CH1) as alternate function*/
	gpio_init(ICU_CH_1_Port, GPIO_MODE_IPU, GPIO_OSPEED_MAX, ICU_CH_1_Pin);
	
	timer_deinit(TIMER2);
	/* initialize TIMER init parameter struct */
	timer_struct_para_init(&timer_initpara);
	/* TIMER2 configuration */
	timer_initpara.prescaler         = ICU_PRESCALER;
	timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection  = TIMER_COUNTER_UP;
	timer_initpara.period            = ICU_COUNTER_MAX;
	timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
	timer_init(TIMER2, &timer_initpara);

	/* TIMER2  configuration */
	/* initialize TIMER channel input parameter struct */
	timer_channel_input_struct_para_init(&timer_icinitpara);
	
	/* TIMER2 CH0 input capture configuration */
	timer_icinitpara.icpolarity  = TIMER_IC_POLARITY_RISING;
	timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
	timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
	timer_icinitpara.icfilter    = 0x0;
	timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
	
	/* TIMER2 CH1 input capture configuration */
	timer_icinitpara.icpolarity  = TIMER_IC_POLARITY_FALLING;
	timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
	timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
	timer_icinitpara.icfilter    = 0x0;
	timer_input_capture_config(TIMER2,TIMER_CH_1,&timer_icinitpara);

	/* auto-reload preload enable */
	timer_auto_reload_shadow_enable(TIMER2);
	
	/* clear channel 0 interrupt bit */
	timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH0);
	/* clear channel 1 interrupt bit */
	timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH1);
	
	/* channel 0 interrupt enable */
	timer_interrupt_enable(TIMER2,TIMER_INT_CH0);
	/* channel 1 interrupt enable */
	timer_interrupt_enable(TIMER2,TIMER_INT_CH1);
	
	nvic_irq_enable(TIMER2_IRQn, 1, 1);
	/* TIMER2 counter enable */
	timer_enable(TIMER2);
}
#endif

/**
  * @brief  PWM输出超时处理
  * @param  None
  * @retval None
  */
static void IcuDriver_TimeoutProcess(void)
{
	/* PWM周期检测超时，将period和duty设置为0 */
	if (icuCtrlInfo.outputTimeout.periodCount == 0)
	{
		icuCtrlInfo.periodInfo.period = 0;
		icuCtrlInfo.dutyInfo.duty = 0;
	}
	/* 占空比检测超时，将duty设为0 */
	else if (icuCtrlInfo.outputTimeout.dutyCount == 0)
	{
		icuCtrlInfo.dutyInfo.duty = 0;
	}
	else
	{
		/* nop */
	}
}

/*****************************************
* 接口函数
*****************************************/
/**
  * @brief  Icu初始化
  * @param  None
  * @retval None
  */
void IcuDriver_Init(void)
{
	/* 1. Icu参数初始化 */
	IcuDriver_ParameterInit();

	/* 2. Icu定时器初始化 */
	IcuDriver_Timer2Init();
}

/**
  * @brief  轮询任务
  * @param  None
  * @retval None
  */
void IcuDriver_PollTask(void)
{
	/* 1. PWM输出超时处理 */
	IcuDriver_TimeoutProcess();
}

/**
  * @brief  周期超时计数自减-10ms周期执行
  * @param  None
  * @retval None
  */
void IcuDriver_PeriodTimeoutSelf(void)
{
	if (icuCtrlInfo.outputTimeout.periodCount > 0)
	{
		icuCtrlInfo.outputTimeout.periodCount--;
	}
	else
	{
		/* nop */
	}
}

/**
  * @brief  周期超时计数自减-10ms周期执行
  * @param  None
  * @retval None
  */
void IcuDriver_DutyTimeoutSelf(void)
{
	if (icuCtrlInfo.outputTimeout.dutyCount > 0)
	{
		icuCtrlInfo.outputTimeout.dutyCount--;
	}
	else
	{
		/* nop */
	}
}

/**
  * @brief  获取PWM周期，周期=1/ICU_FREQ*IcuDriver_GetPeriod()
  * @param  None
  * @retval None
  */
uint16 IcuDriver_GetPeriod(void)
{
	return icuCtrlInfo.periodInfo.period;
}

/**
    * @brief  获取PWM占空比，占空比=1/ICU_FREQ*IcuDriver_GetDuty()
	*	      此数据为高电平计数值，实际占空比=IcuDriver_GetDuty()/IcuDriver_GetPeriod()
	* @param  None
	* @retval None
  */
uint16 IcuDriver_GetDuty(void)
{
	return icuCtrlInfo.dutyInfo.duty;
}

/**
  * @brief  This function handles TIMER2 interrupt request.
  * @param  None
  * @retval None
  */
void TIMER2_IRQHandler(void)
{
	if (timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_CH0) == SET)
	{
		/* clear channel 0 interrupt bit */
		timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0);
		
		/* 重置周期检测超时时间 */
		icuCtrlInfo.outputTimeout.periodCount = PWM_OUTPUT_TIMEOUT_TIME;
		/* 记录每次上升沿时的计数值，用于占空比计算 */
		icuCtrlInfo.dutyInfo.riseCounter = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_0);
		
		/* 记录第一次上升沿计数 */
		if (icuCtrlInfo.periodInfo.PPState == FALSE)
		{
			/* read channel 0 capture value */
			icuCtrlInfo.periodInfo.pingCounter = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_0);
			icuCtrlInfo.periodInfo.PPState = TRUE;
		}
		/* 记录第二次上升沿计数，周期为两次计数相减 */
		else
		{
			/* read channel 0 capture value */
			icuCtrlInfo.periodInfo.pongCounter = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_0);

			if (icuCtrlInfo.periodInfo.pongCounter > icuCtrlInfo.periodInfo.pingCounter)
			{
				icuCtrlInfo.periodInfo.period = (icuCtrlInfo.periodInfo.pongCounter - icuCtrlInfo.periodInfo.pingCounter); 
			}
			else
			{
				icuCtrlInfo.periodInfo.period = ((ICU_COUNTER_MAX - icuCtrlInfo.periodInfo.pingCounter) + icuCtrlInfo.periodInfo.pongCounter); 
			}
			
			icuCtrlInfo.periodInfo.PPState = FALSE;
		}
	}
	else if (timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_CH1) == SET)
	{
		/* clear channel 1 interrupt bit */
		timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH1);
		
		/* 重置占空比检测超时时间 */
		icuCtrlInfo.outputTimeout.dutyCount = PWM_OUTPUT_TIMEOUT_TIME;
		/* 记录下降沿计数 */
		icuCtrlInfo.dutyInfo.downCounter = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_1);
		
		/* 当周期不为0时，占空比才有意义 */
		if (icuCtrlInfo.periodInfo.period != 0)
		{
			/* 计算占空比，占空比=下降沿计数-上升沿计数 */
			if (icuCtrlInfo.dutyInfo.downCounter > icuCtrlInfo.dutyInfo.riseCounter)
			{
				icuCtrlInfo.dutyInfo.duty = (icuCtrlInfo.dutyInfo.downCounter - icuCtrlInfo.dutyInfo.riseCounter); 
			}
			else
			{
				icuCtrlInfo.dutyInfo.duty = ((ICU_COUNTER_MAX - icuCtrlInfo.dutyInfo.riseCounter) + icuCtrlInfo.dutyInfo.downCounter); 
			}
		}
		else
		{
			icuCtrlInfo.dutyInfo.duty = 0;
		}
	}
	else
	{
		/* nop */
	}
}

/* *********************需要做异常处理（5s没有进周期中断，周期和占空比都置0；周期中断正常，但是5s没有进占空比中断，占空比置0）********************************* */

/********************************* END OF FILE ********************************/
